/* 
 * File:   TupleK.cpp
 * Author: hamed
 * 
 * Created on October 29, 2010, 1:56 PM
 */

#include <sstream>

#include "TupleK.h"

TupleK::TupleK(int k) {
    tupleLength = k;
    tuple = new LogicValue[tupleLength];
    setTuple(logic_invalid);
    allOne = false;
    allZero = false;
    tupleUpdated = false;
}


TupleK::~TupleK() {
//    cout << "Calling destructor\n";
    delete[] tuple;
}

LogicValue TupleK::GetValueAt(int index) const {
    return tuple[index];
}

unsigned long long int TupleK::getValueAsInt(){
    unsigned long long int res = 0;
    for(int i=tupleLength-1;i>=0;i--){
        res <<= 1;
        if(tuple[i] == logic_1)
            res |= 1;
    }
    return res;
}

void TupleK::SetValueAt(int index, LogicValue value) {
    tuple[index] = value;
    tupleUpdated = true;
}

void TupleK::setTuple(int value){
    allOne = (value & 1)?true:false;
    allZero = (value & 1)?false:true;
    for(int i=0;i<tupleLength;i++){
        tuple[i] = (value & 1)?logic_1:logic_0;
        if(allOne && !(value & 1)){
            allOne = false;
        }
        if(allZero && (value & 1)){
            allZero = false;
        }
        value >>= 1;
    }
}

void TupleK::setTuple(LogicValue value){
    for(int i=0;i<tupleLength;i++){
        tuple[i] = value;
    }
    allOne = allZero = false;
    if(value == logic_1){
        allOne = true;
    }
    else if(value == logic_0){
        allZero = true;
    }
}

void TupleK::setTuple(TupleK* t){
    allOne = true;
    allZero = false;
    int i= (t->tupleLength >= this->tupleLength)?tupleLength-1:t->tupleLength-1;
    for(int j=tupleLength-1;j>i;j--){
        tuple[j] = logic_0;
        allOne = false;
        allZero = true;
    }
    for(; i>=0; i--){
        tuple[i] = t->GetValueAt(i);
        if(tuple[i] != logic_1)
            allOne = false;
        if(tuple[i] != logic_0)
            allZero = false;
    }
    return;
}

//bool TupleK::isValid(){
//    for(int i=0;i<tupleLength;i++){
//        if(tuple[i] == logic_invalid)
//            return false;
//    }
//    return true;
//}


bool TupleK::containsLogic(){
    for(int i=0;i<tupleLength;i++){
        if(tuple[i] != logic_invalid)
            return true;
    }
    return false;
}

bool TupleK::isAllOne(){
    if(tupleUpdated){
        allOne = true;
        for(int i=0;i<tupleLength;i++){
            if(tuple[i] != logic_1)
                allOne = false;
        }
        tupleUpdated = false;
    }
    return allOne;
}

bool TupleK::isAllZero(){
    if(tupleUpdated){
        allZero = true;
        for(int i=0;i<tupleLength;i++){
            if(tuple[i] != logic_0)
                allZero = false;
        }
        tupleUpdated = false;
    }
    return allZero;
}

void TupleK::print(){
    for(int i=tupleLength-1;i>=0;i--){
        cout << (char)tuple[i];
    }
    cout << endl;
}
int TupleK::GetTupleLength() const {
    return tupleLength;
}

    char* TupleK::getFunction(){
    stringstream function("");
    for(int i=tupleLength-1;i>=0;i--){
        if(tuple[i] == logic_invalid)
            continue;
        function << "x" << i;
        if(tuple[i] == logic_0){
            function << "'";
        }
    }
    return (char*)function.str().c_str();
}

bool TupleK::operator ==(TupleK* t){
    if(t->GetTupleLength()!=tupleLength)
        return false;
    for(int i=0; i< tupleLength; i++){
        if(t->GetValueAt(i) != tuple[i]){
            return false;
        }
    }
    return true;
}

bool TupleK::operator !=(TupleK t){
    for(int i=0; i< tupleLength; i++){
        if(t.GetValueAt(i) != tuple[i])
            return true;
    }
    return false;
}

// meaning that they are inverse of each other in case of bit positions
bool TupleK::operator%=(TupleK t){
    for(int i=0; i< tupleLength; i++){
//        cout << i << endl;
        if(t.GetValueAt(i)==logic_invalid || tuple[i]==logic_invalid)
            return false;
        if(t.GetValueAt(i) == tuple[i])
            return false;
    }
    return true;
}

TupleK* TupleK::operator>>(int shr){
    TupleK* t= new TupleK(this->tupleLength);

    if(shr == 0){
        delete t;
        return this;
    }else if(shr > tupleLength){
        t->setTuple(logic_0);
        return t;
    }
    int i= tupleLength-1;
    for(;i>tupleLength-shr-1; i--){
        t->SetValueAt(i, logic_0);
    }
    for(; i>=0; i--){
        t->SetValueAt(i, tuple[i+shr]);
    }
    return t;
}

TupleK TupleK::operator <<(int shl){
    TupleK t(this->tupleLength);

    if(shl == 0){
        return *this;
    }else if(shl > tupleLength){
        t.setTuple(logic_0);
        return t;
    }

    int i= tupleLength-1;
    for(; i>shl-1; i--){
        t.SetValueAt(i, tuple[i-shl]);
    }
    for(;i>=0; i--){
        t.SetValueAt(i, logic_0);
    }

    return t;
}

TupleK* TupleK::operator &=(TupleK t){
    TupleK* res = new TupleK(tupleLength);
    LogicValue bitValue;
    for(int i=0; i<tupleLength; i++){
        if(t.GetValueAt(i) == logic_invalid && tuple[i] == logic_invalid){
            bitValue = logic_invalid;
        }
        else if(t.GetValueAt(i) == logic_0 || tuple[i] == logic_0){
            bitValue = logic_1;
        }
        else if(t.GetValueAt(i) == logic_1 && tuple[i] == logic_1){
            bitValue = logic_1;
        }
        res->SetValueAt(i, bitValue);
    }

    return res;
}